package com.hubu.controller;


import com.csvreader.CsvWriter;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hubu.config.WebAppConfig;
import com.hubu.domain.KgDomain;
import com.hubu.domain.KgNodeDetail;
import com.hubu.domain.User;
import com.hubu.model.NodeItem;
import com.hubu.request.*;
import com.hubu.result.R;
import com.hubu.service.KgGraphService;
import com.hubu.service.KnowledgeGraphService;
import com.hubu.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.*;
/**
 * @description: 三元组相关接口
 * @author: hubu
 * @Date: 2022/11/5
 */
@RestController
public class KGManagerController {
    @Autowired
    private WebAppConfig config;
    @Autowired
    private KgGraphService kgGraphService;
    @Autowired
    private KnowledgeGraphService kgService;

    @ResponseBody
    @RequestMapping(value = "/exportGraph")
    public Map<String,Object> exportGraph(HttpServletRequest request) {
        Map<String,Object> res=new HashMap<>();
        String label = request.getParameter("domain");
        String filePath = config.getLocation();
        String fileName = UUID.randomUUID() + ".csv";
        String fileUrl = filePath + fileName;
        String cypher = String.format(
                "MATCH (n) -[r]->(m) return n.name as source,r.name as relation, m.name as target");
        List<HashMap<String, Object>> list = Neo4jUtil.getGraphTable(cypher);
        if(list.size()==0){
            res.put("code", -1);
            res.put("message", "该领域没有任何有关系的实体!");
            return res;
        }
        try {
            FileUtil.createFile(fileUrl);
            CsvWriter csvWriter = new CsvWriter(fileUrl, ',', StandardCharsets.UTF_8);
            String[] header = {"source", "target", "relation"};
            csvWriter.writeRecord(header);
            for (HashMap<String, Object> hashMap : list) {
                int colSize = hashMap.size();
                String[] cntArr = new String[colSize];
                cntArr[0] = hashMap.get("source").toString().replace("\"", "");
                cntArr[1] = hashMap.get("target").toString().replace("\"", "");
                cntArr[2] = hashMap.get("relation").toString().replace("\"", "");
                try {
                    csvWriter.writeRecord(cntArr);
                } catch (IOException e) {
                    System.out.println("CSVUtil->createFile: 文件输出异常" + e.getMessage());
                }
            }
            csvWriter.close();
            String serverUrl = request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
            String csvUrl = "/file/download/" + fileName;

            res.put("code", 200);
            res.put("fileName", csvUrl);
            res.put("message", "success!");
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return res;

    }



    /**
     * 创建孩子节点
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping("/batchCreateChildNode")
    public R batchCreateChildNode(@RequestBody BatchCreateNodeItem request) {
        HashMap<String, Object> rss = new HashMap<String, Object>();
        String[] tNames=request.getTargetNames().split(",");
        rss = kgGraphService.batchCreateChildNode(request.getDomain(), request.getSourceId(), request.getEntityType(), tNames, request.getRelation());
        return R.ok().data(rss);
    }

    /**
     * 获取当前节点对应的内容
     * @param domainId
     * @param nodeId
     * @return
     */
    @ResponseBody
    @PostMapping("/getNodeContent")
    public R getNodeContent(int domainId, int nodeId) {
        List<KgNodeDetail> contents = kgService.getNodeContent(domainId, nodeId);
        if (contents != null && contents.size() > 0) {
            return R.ok().data("content",contents.get(0));
        }
        return R.ok().data("list",new ArrayList<>());
    }

    /**
     * 保存节点对应的内容
     * @param params
     * @return
     */
    @ResponseBody
    @PostMapping("/saveNodeContent")
    public R saveNodeContent(@RequestBody Map<String, Object> params) {
        try {
            String username = "xiedi";
            int domainId = (int) params.get("domainId");
            String nodeId = params.get("nodeId").toString();
            String content = params.get("content").toString();
            List<KgDomain> domainList = kgService.getDomainById(domainId);
            if (domainList != null && domainList.size() > 0) {
                String domainName = domainList.get(0).getName();
                // 检查是否存在
                List<KgNodeDetail> items = kgService.getNodeContent(domainId, Integer.parseInt(nodeId));
                if (items != null && items.size() > 0) {
                    KgNodeDetail oldItem = items.get(0);
                    Map<String, Object> item = new HashMap<String, Object>();
                    item.put("domainId", oldItem.getDomainId());
                    item.put("nodeId", oldItem.getNodeId());
                    item.put("content", content);
                    item.put("modifyUser", username);
                    item.put("modifyTime", DateUtil.getDateNow());
                    kgService.updateNodeContent(item);
                    return R.ok().message("更新成功");
                } else {
                    Map<String, Object> sb = new HashMap<String, Object>();
                    sb.put("content", content);
                    sb.put("domainId", domainId);
                    sb.put("nodeId", nodeId);
                    sb.put("status", 1);
                    sb.put("createUser", username);
                    sb.put("createTime", DateUtil.getDateNow());
                    if (sb.size() > 0) {
                        kgService.saveNodeContent(sb);
                        return R.ok().message("保存成功");
                    }
                }
                // 更新到图数据库,表明该节点有附件,加个标识,0=没有,1=有
                kgGraphService.updateNodeFileStatus(domainName, Long.parseLong(nodeId), 1);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return R.error().message(e.getMessage());
        }
        return R.error().message("操作失败");
    }

    @ResponseBody
    @PostMapping("/updateCoordinateOfNode")
    public R updateCoordinateOfNode(@RequestBody NodeCoordinateSubmitItem request) {
        try {
            String domain=request.getDomain();
            List<NodeCoordinateItem> nodes = request.getNodes();
            kgGraphService.batchUpdateGraphNodesCoordinate(domain,nodes);
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            return R.error().message(e.getMessage());
        }
    }

    @ResponseBody
    @DeleteMapping("/deleteLink")
    public R deleteLink(String domain, long shipId) {
        kgGraphService.deleteLink(domain, shipId);
        return R.ok().message("三元组关系删除成功！");
    }

    /**
     * 删除某领域知识图谱以及下属所有节点与关系
     * @param domainId
     * @param domain
     * @return
     */
    @ResponseBody
    @DeleteMapping("/deleteDomain")
    public R deleteDomain(Integer domainId, String domain) {
        kgService.deleteDomain(domainId);
        kgGraphService.deleteKGDomain(domain);
        return R.ok().message("删除成功！");
    }

    /**
     * 新增节点
     * @param entity: domain name
     * @return
     */
    @ResponseBody
    @PostMapping("/createNode")
    public R createNode(@RequestBody NodeItem entity) {
        HashMap<String, Object> graphNode = new HashMap<String, Object>();
        graphNode = kgGraphService.createNode(entity.getDomain(), entity);
        if (graphNode != null && graphNode.size() > 0) {
            return R.ok().data(graphNode);
        }
        return R.error().message("操作失败");
    }

    /**
     * 修改节点名称
     * @param request
     * @return
     */
    @ResponseBody
    @PutMapping("/updateNodeName")
    public R updateNodeName(@RequestBody KgNodeItem request) {

        HashMap<String, Object> graphNodeList = new HashMap<String, Object>();
        if (!StringUtil.isBlank(request.getDomain())) {
            graphNodeList = kgGraphService.updateNodeName(request.getDomain(), request.getNodeId(), request.getNodeName());
            if (graphNodeList.size() > 0) {
                return R.ok().data(graphNodeList);
            }
        }
        return R.error().message("操作失败");
    }

    /**
     * 获取某节点的记录数
     * @param domain
     * @param nodeId
     * @return
     */
    @ResponseBody
    @GetMapping("/getRelationNodeCount")
    public R getRelationNodeCount(String domain, long nodeId) {
        long totalCount = 0;
        if (!StringUtil.isBlank(domain)) {
            totalCount = kgGraphService.getRelationNodeCount(domain, nodeId);
            return R.ok().data("totalCount",totalCount);
        }
        return R.error().message("操作失败");
    }

    /**
     * 查询某节点的关联节点与关系
     * @param domain
     * @param nodeId
     * @return
     */
    @ResponseBody
    @GetMapping("/getMoreRelationNode")
    public R getMoreRelationNode(String domain, String nodeId,Integer round) {
        if (!StringUtil.isBlank(domain)) {
            HashMap<String, Object> graphModel = kgGraphService.getMoreRelationNode(domain, nodeId, round);
            if (graphModel != null) {
                return R.ok().data(graphModel);
            }
        }
        return R.error().message("没有更多数据了");
    }

    /**
     * 删除某节点
     * @param domain
     * @param nodeId 节点Id
     * @return
     */
    @ResponseBody
    @DeleteMapping("/deleteNode")
    public R deleteNode(String domain, long nodeId) {
        HashMap List = kgGraphService.deleteNode(domain, nodeId);
        return R.ok().data("List",List);
    }

    /**
     * 针对已存在的两个节点 创建三元组关系
     * @param request:domain 首尾节点id 所需的关系名称
     * @return
     */
    @ResponseBody
    @PostMapping("/createLink")
    public R createLink(@RequestBody CreateLinkItem request) {
        HashMap<String, Object> cypherResult = kgGraphService.createLink(request.getDomain(), request.getTargetDomain(), request.getSourceId(), request.getTargetId(), request.getShip());
        return R.ok().data(cypherResult);
    }

    /**
     * 给定头节点uuid，尾节点列表（,隔开） 批量生成同名称的三元组
     * @param request
     * @return
     */
    @ResponseBody
    @PostMapping("/batchCreateNode")
    public R batchCreateNode(@RequestBody BatchCreateNodeItem request) {
        HashMap<String, Object> rss = new HashMap<String, Object>();
        String[] tNames=request.getTargetNames().split(",");
        rss = kgGraphService.batchCreateNode(request.getDomain(), request.getSourceName(), request.getSourceId(), request.getRelation(),tNames);
        if (rss.size() > 0 ){
            return R.ok().data(rss);
        }else {
            return R.ok().message("头节点:" + request.getSourceName() + "不存在");
        }

    }

    /**
     * 修改三元组之间的关系
     * @param domain 某领域
     * @param shipId 关系id
     * @param shipName 新关系名称
     * @return
     */
    @ResponseBody
    @PutMapping("/updateLink")
    public R updateLink(String domain, long shipId, String shipName) {
        HashMap<String, Object> cypherResult = kgGraphService.updateLink(domain, shipId, shipName);
        return R.ok().data(cypherResult);
    }
    /**
     * 获取某领域下特定数量的知识图谱三元组
     * @param query
     * @return
     */
    @ResponseBody
    @GetMapping("/getDomainGraph")
    public R getDomainGraph(GraphQuery query) {
        HashMap<String, Object> graphData = kgGraphService.getDomainGraph(query);
        return R.ok().data(graphData);
    }

    /**
     * 查询节点与节点数量
     * @param nodeItem
     * @return
     */
    @ResponseBody
    @RequestMapping("/searchEntities")
    public R searchEntities(NodeItem nodeItem){
        HashMap<String, Object> nodeData = kgGraphService.getNodes(nodeItem);
        return R.ok().data(nodeData);
    }

    @ResponseBody
    @GetMapping("/competeCompany")
    public R getCompeteCompany(@RequestParam String nodeName,
                               @RequestParam String nodeId){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setNodeName(nodeName);
        nodeItem.setNodeId(nodeId);
        HashMap<String, Object> nodeData = kgGraphService.getCompeteCompany(nodeItem);
        return R.ok().data(nodeData);
    }


    @ResponseBody
    @GetMapping("/cooperateCompany")
    public R cooperateCompany(@RequestParam String nodeName,
                              @RequestParam String nodeId,
                              @RequestParam String flag
    ){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setNodeName(nodeName);
        nodeItem.setNodeId(nodeId);
        nodeItem.setFlag(flag);
        HashMap<String, Object> nodeData = kgGraphService.getcooperateCompany(nodeItem);
        return R.ok().data(nodeData);
    }

    /**
     * 根据cql查询节点的合作、竞争图谱
     * @param nodeItem cql
     * @return
     */
    @ResponseBody
    @PostMapping("/hiddenRelation")
    public R hiddenRelation(@RequestBody NodeItem nodeItem){
        HashMap<String, Object> nodeDataAndRel = kgGraphService.getHiddenRelation(nodeItem);
        return R.ok().data(nodeDataAndRel);
    }
    @ResponseBody
    @GetMapping("/companyRisk")
    public R companyRisk(@RequestParam String nodeName,@RequestParam String nodeId){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setNodeName(nodeName);
        nodeItem.setNodeId(nodeId);
        HashMap<String, Object> nodeData = kgGraphService.getCompanyRisk(nodeItem);
        //ArrayList<HashMap<String,Object>> replaceCompany = (ArrayList<HashMap<String,Object>>)nodeData.get("replaceCompany");
        return R.ok().data(nodeData);
    }
    @ResponseBody
    @GetMapping("/companyProduct")
    public R companyProduct(@RequestParam String nodeName){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setNodeName(nodeName);
        HashMap<String, Object> product = kgGraphService.getCompanyProduct(nodeItem);
        return R.ok().data(product);
    }
    @ResponseBody
    @RequestMapping("/searchEntityLinks")
    public R searchEntityLinks(NodeItem nodeItem){
        HashMap<String, Object> nodeData = kgGraphService.getEntityLinks(nodeItem);
        return R.ok().data(nodeData);
    }
    @ResponseBody
    @RequestMapping("/stockList")
    public R getStockList(@RequestParam Integer page,@RequestParam Integer pageSize){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setPage(page);
        nodeItem.setPageSize(pageSize);
        HashMap<String, Object> stockList = kgGraphService.getStockList(nodeItem);
        return R.ok().data(stockList);
    }
    @ResponseBody
    @RequestMapping("/etfList")
    public R getEtfList(@RequestParam Integer page,@RequestParam Integer pageSize){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setPage(page);
        nodeItem.setPageSize(pageSize);
        HashMap<String, Object> etfList = kgGraphService.getEtfList(nodeItem);
        return R.ok().data(etfList);
    }
    @ResponseBody
    @RequestMapping("/historyStock")
    public R getHistoryStock(@RequestParam String code){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setCode(code);
        HashMap<String, Object> stockList = kgGraphService.getHistoryStock(nodeItem);
        return R.ok().data(stockList);
    }
    @ResponseBody
    @RequestMapping("/historyEtf")
    public R getHistoryEtf(@RequestParam String code){
        NodeItem nodeItem = new NodeItem();
        nodeItem.setCode(code);
        HashMap<String, Object> etfList = kgGraphService.getHistoryEtf(nodeItem);
        return R.ok().data(etfList);
    }
    @ResponseBody
    @RequestMapping("/stock")
    public R getStock(NodeItem nodeItem){
        HashMap<String, Object> stock = kgGraphService.getStock(nodeItem);
        return R.ok().data(stock);
    }
    @ResponseBody
    @RequestMapping("/etf")
    public R getEtf(NodeItem nodeItem){
        HashMap<String, Object> etf = kgGraphService.getEtf(nodeItem);
        return R.ok().data(etf);
    }
    @ResponseBody
    @RequestMapping("/getEtfLink")
    public R getEtfLink(@RequestParam String number){
        HashMap<String, Object> nodeData = kgGraphService.getEtfLink(number);
        return R.ok().data(nodeData);
    }
    @ResponseBody
    @RequestMapping("/getLocalProductLink")
    public R articulationProductGraph(@RequestParam String productName){
        HashMap<String, Object> nodeData = kgGraphService.getArticulationProductGraph(productName);
        return R.ok().data(nodeData);
    }
    /**
     * 创建领域标签
     * @param domain
     * @param type
     * @return
     */
    @ResponseBody
    @PostMapping("/createDomain")
    public R createDomain(String domain,Integer type) {
        if (!StringUtil.isBlank(domain)) {
            List<KgDomain> domainItem = kgService.getDomainByName(domain);
            System.out.println(domainItem);
            if (domainItem.size() > 0) {
                return R.error().message("领域已存在");
            } else {
                int domainId= kgService.quickCreateDomain(domain,type);// 保存到mysql
                kgGraphService.createDomain(domain);// 保存到图数据
                return R.ok().data("domainId",domainId);
            }
        }
        return R.ok();
    }

    /**
     * 获取当前所有领域知识图谱标签
     * @param queryItem
     * @return 数据库字段
     */
    @ResponseBody
    @GetMapping("/getGraph") // call db.labels
    public R getGraph( GraphQuery queryItem) {
        GraphPageRecord<KgDomain> resultRecord = new GraphPageRecord<KgDomain>();
        PageHelper.startPage(queryItem.getPageIndex(), queryItem.getPageSize(), true);
        List<KgDomain> domainList = kgService.getDomainList(queryItem.getDomain(), queryItem.getType(),queryItem.getCommend());
        PageInfo<KgDomain> pageInfo = new PageInfo<KgDomain>(domainList);
        long total = pageInfo.getTotal();
        resultRecord.setPageIndex(queryItem.getPageIndex());
        resultRecord.setPageSize(queryItem.getPageSize());
        resultRecord.setTotalCount(new Long(total).intValue());
        resultRecord.setNodeList(pageInfo.getList());
        return R.ok().data("resultRecord",resultRecord);
    }

    /**
     * 导入excel三元组到Neo4j
     * @param file
     * @param request
     * @return
     */
    @ResponseBody
    @PostMapping("/importGraph")
    public R importGraph(@RequestParam(value = "file", required = true)
                         @Validated @NotNull(message = "请上传有效的excel的文件") @Pattern(regexp = "^(?:\\w+\\.xlsx|\\w+\\.xls)$",
            message = "请上传有效的excel的文件")
                                 MultipartFile file,
                         HttpServletRequest request){
        try {
            String label = request.getParameter("domain");
            Integer type = Integer.parseInt(request.getParameter("type"));
            List<KgDomain> domainList = kgService.getDomainByName(label);
            int domainExist=0;
            if(domainList!=null&&domainList.size()>0){
                //导入已有图谱，更新图谱创建时间
                KgDomain domainItem = domainList.get(0);
                domainItem.setModifyTime(DateUtil.getDateNow());
                kgService.updateDomain(domainItem);
                domainExist=1;
            }else{
                label = StringUtil.isBlank(label) ? UuidUtil.getUUID() : label;
                kgService.quickCreateDomain(label,type);// 三元组
            }
            if (type.equals(1)) {//三元组导入
                kgGraphService.importBySyz(file, request, label,domainExist);

            } else {
                kgGraphService.importByCategory(file, request, label);
            }
            return R.ok().message("操作成功");
        } catch (Exception e) {
            e.printStackTrace();
            return R.error().message("处理失败");
        }
    }

    @PostMapping("/showUserInfo")
    public HashMap<String,Object> displayUserInfo(@RequestBody User user){
        String userInfo=user.getUsername()+" "+user.getPhone();
        System.out.println(userInfo);
        HashMap<String,Object> result = new HashMap<>();
        result.put("name",user.getUsername());
        result.put("phone",user.getPhone());
        return result;
    }
}
